import json
from sys import exception
from urllib import parse
from datetime import datetime

from django.db import transaction
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from rest_framework import viewsets, mixins, status, generics
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import exceptions
from django.contrib.auth import get_user_model
from apps.oaauth.models import OADepartment, UserStatusChoices
from apps.oaauth.serializers import DepartmentSerializer, UserSerializer
from apps.staff.serializers import AddStaffSerializer, ActiveStaffSerializer, StaffUploadSerializer
from django.core.mail import send_mail
from django.conf import settings
from utils import aeser
from django.urls import reverse
from oaback.celery import debug_task
from .paginations import StaffListPagination
from .tasks import send_mail_task
from openpyxl import Workbook
from openpyxl import load_workbook
from django.http import HttpResponse

OAUser = get_user_model()
aes = aeser.AESCipher(settings.SECRET_KEY)


def send_active_email(request, email):
    token = aes.encrypt(email)
    active_path = reverse("staff:active_staff") + "?" + parse.urlencode({'token': token})
    # # http://127.0.0.1:8000/staff/active?token=xxx
    active_url = request.build_absolute_uri(active_path)

    message = f"请点击以下链接激活账号: {active_url}"
    subject = "[OAMS]账号激活"

    # 发送邮件
    # send_mail(
    #     subject=subject,
    #     recipient_list=[email],
    #     message=message,
    #     from_email=settings.DEFAULT_FROM_EMAIL,
    # )

    # 使用celery异步发送邮件
    send_mail_task(email=email, subject=subject, message=message)


class ActiveStaffView(View):
    def get(self, request):
        token = request.GET.get('token')
        response = render(request, 'active.html')
        response.set_cookie('token', token)
        return response

    def post(self, request):
        try:
            token = request.COOKIES.get('token')
            email = aes.decrypt(token)
            serializer = ActiveStaffSerializer(data=request.POST)
            if serializer.is_valid():
                form_email = serializer.validated_data.get('email')
                user = serializer.validated_data.get('user')
                if email != form_email:
                    return JsonResponse({"code": 400, "message": "邮箱错误！"})
                user.status = UserStatusChoices.ACTIVED
                user.save()
                return JsonResponse({"code": 200, "message": ""})
            else:
                detail = list(serializer.errors.values())[0][0]
                return JsonResponse({"code": 400, "message": detail})

        except Exception as e:
            print(str(e))
            return JsonResponse({"code": 400, "message": "token错误！"})


# Create your views here.
class DepartmentListView(ListAPIView):
    queryset = OADepartment.objects.all().order_by('id')
    serializer_class = DepartmentSerializer


class StaffViewSet(viewsets.GenericViewSet,
                   mixins.CreateModelMixin,
                   mixins.ListModelMixin,
                   mixins.UpdateModelMixin):
    queryset = OAUser.objects.all()
    pagination_class = StaffListPagination

    def get_serializer_class(self):
        if self.request.method in ['GET', 'PUT']:
            return UserSerializer
        else:
            return AddStaffSerializer

    # 获取员工列表
    def get_queryset(self):
        department_id = self.request.query_params.get('department_id')
        realname = self.request.query_params.get('realname')
        date_joined = self.request.query_params.getlist('date_joined[]')

        queryset = self.queryset
        # 返回员工列表的逻辑
        # 1. 如果是管理员返回所有员工
        # 2. 如果不是管理员, 但是是部门领导, 返回部门所有员工
        # 3. 如果不是董事会, 也不是部门领导, 就抛出403 Forbidden错误
        user = self.request.user
        if user.department.name != "管理员":
            if user.uid != user.department.leader.uid:
                raise exceptions.PermissionDenied()
            else:
                queryset = queryset.filter(department_id=user.department_id)
        else:
            # 管理员中，根据部门id进行过滤
            if department_id:
                queryset = queryset.filter(department_id=department_id)
        if realname:
            queryset = queryset.filter(realname=realname)
        if date_joined:
            # ['2024-10-01', '2024-10-10']
            try:
                start_date = datetime.strptime(date_joined[0], "%Y-%m-%d")
                end_date = datetime.strptime(date_joined[1], "%Y-%m-%d")
                queryset = queryset.filter(date_joined__range=(start_date, end_date))
            except Exception as e:
                print(e)
        return queryset.order_by('-date_joined').all()

    def create(self, request, *args, **kwargs):
        # 如果用的是视图集，那么视图集会自动把request放到context中
        # 如果是直接继承自APIView，那么就需要手动将request对象传给serializer.context中
        serializer = AddStaffSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            realname = serializer.validated_data['realname']
            email = serializer.validated_data['email']
            password = serializer.validated_data['password']

            user = OAUser.objects.create_user(realname, email, password)
            department = request.user.department
            user.department = department
            user.save()
            # 发送激活邮件
            # send_active_email(request, email)
            return Response({"email": email}, status=status.HTTP_201_CREATED)
        else:
            return Response(data={list(serializer.errors.values())[0][0]}, status=status.HTTP_400_BAD_REQUEST)

    def update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return super().update(request, *args, **kwargs)


class StaffDownloadView(APIView):
    def get(self, request):
        pks = request.query_params.get('pks')
        try:
            pks = json.loads(pks)
        except Exception as e:
            print(e)
            return Response({"detail": "员工参数错误！"}, status=status.HTTP_400_BAD_REQUEST)

        try:
            current_user = request.user
            queryset = OAUser.objects
            if current_user.department.name != "管理员":
                if current_user.uid != current_user.department.leader.uid:
                    return Response({'detail': "没有权限下载！"}, status=status.HTTP_403_FORBIDDEN)
                else:
                    queryset = queryset.filter(department_id=current_user.department_id)
            queryset = queryset.filter(pk__in=pks)
            result = queryset.values("realname", "email", "department__name", 'date_joined', 'status')
            # 创建一个工作簿和一个工作表
            wb = Workbook()
            ws = wb.active
            ws.title = "user_table"

            # 写入标题行
            ws.append(['姓名', '邮箱', '部门', '入职时间', '状态'])
            for r in result:
                ws.append([r["realname"], r["email"], r["department__name"], r["date_joined"], r["status"]])

            # 准备响应
            response = HttpResponse(content_type='application/xlsx')
            response['Content-Disposition'] = "attachment; filename=员工信息.xlsx"

            # 将工作簿写入响应
            wb.save(response)
            return response

        except Exception as e:
            print(e)
            return Response({"detail": str(e)}, status=status.HTTP_400_BAD_REQUEST)


class StaffUploadView(APIView):
    def post(self, request):
        serializer = StaffUploadSerializer(data=request.data)
        if serializer.is_valid():
            file = serializer.validated_data.get('file')
            current_user = request.user
            if current_user.department.name != '管理员' or current_user.department.leader_id != current_user.uid:
                return Response({"detail": "您没有权限访问！"}, status=status.HTTP_403_FORBIDDEN)
            # 加载工作簿
            workbook = load_workbook(file)
            sheet = workbook.active
            users = []
            # 遍历工作表中的行，跳过标题行
            for row in sheet.iter_rows(min_row=2, values_only=True):
                # 林冲2 linchong2@song.com 开发部 123456
                print(row[0], row[1], row[2], row[3])
                # 获取部门
                if current_user.department.name != '管理员':
                    department = current_user.department
                else:
                    try:
                        department = OADepartment.objects.filter(name=row[2]).first()
                        if not department:
                            return Response({"detail": f"{row[2]}不存在"}, status=status.HTTP_400_BAD_REQUEST)
                    except Exception as e:
                        print(e)
                        return Response({"detail": "部门不存在!"}, status=status.HTTP_400_BAD_REQUEST)
                try:
                    realname = row[0]
                    email = row[1]
                    password = str(row[3])
                    user = OAUser(email=email, realname=realname, department=department,
                                  status=UserStatusChoices.UNACTIVE)
                    user.set_password(password)
                    users.append(user)
                except Exception as e:
                    print(e)
                    return Response({"detail": "请检查文件中的姓名, 邮件, 部门名称!"},
                                    status=status.HTTP_400_BAD_REQUEST)
            try:
                # 开启事务操作
                with transaction.atomic():
                    OAUser.objects.bulk_create(users)
            except Exception as e:
                print(e)
                return Response({"detail": "员工添加错误!"}, status=status.HTTP_400_BAD_REQUEST)
            # 异步给每个新增的员工发送邮件
            # for user in users:
            #     send_active_email(request, user.email)
            return Response()

        else:
            detail = list(serializer.errors.values())[0][0]
            return Response({"detail": detail}, status=status.HTTP_400_BAD_REQUEST)


class TestCeleryView(APIView):
    def get(self, request):
        # 用celery异步执行debug_task这个任务
        debug_task.delay()
        return Response({"detail": "SUCCESS!"})
